from django.utils.translation import ugettext_lazy as _
from django.db.models import fields, get_model
from django.http import HttpResponse, Http404
from django.template import loader, Context
from django.conf import settings

from urllib import urlencode
import urlparse
import simplejson
import libxml2

from results import ResultList
from parser import parse_description

__all__ = ["description", "results_html", "results_json", "results_kml"]

##
## utility functions
##
def get_model_or_404(app_label, model_name):
    model = get_model(app_label, model_name)
    if not model:
        raise Http404("No such model")
    if not hasattr(model._meta, "search") or not model._meta.search:
        raise Http404("No search")
    return model

def get_display_labels(model):
    for field_name in model._meta.search.display_fields:
        try:
            field = model._meta.get_field_by_name(field_name)[0]
            yield field.verbose_name
            continue
        except fields.FieldDoesNotExist:
            pass
        if hasattr(model, field_name):
            field = getattr(model, field_name)
            if hasattr(field, "short_description"):
                yield field.short_description
                continue
        yield field_name

def get_display_fields(obj):
    for field_name in obj._meta.search.display_fields:
        value = getattr(obj, field_name)
        if callable(value):
            value = value()
        if hasattr(value, "render"):
            value = value.render()
        yield field_name, value

##
## views
##
def description(request, app_label, model_name):
    model = get_model_or_404(app_label, model_name)

    response = HttpResponse()
    response["Content-Type"] = "application/opensearchdescription+xml"
    response["Content-Disposition"] = \
        "attachment; filename=%s_%s_osd.xml" % (app_label, model_name)
    uri = request.build_absolute_uri()    
    t = urlparse.urlsplit(uri)
    host = t[0]+'://'+t[1]
    response.write(model._meta.search.description(host=host))

    return response

def description_json(request, app_label, model_name):
    model = get_model_or_404(app_label, model_name)

    response = HttpResponse()
    response["Content-Type"] = "text/javascript"
    descr = parse_description(model._meta.search.description)
    response.write(simplejson.dumps(descr))

    return response
    
    
def results_html(request, app_label, model_name,
         template = "opensearch/results.html"):
    model = get_model_or_404(app_label, model_name)
    r = ResultList(request, model)
    t = loader.get_template(template)

    query = request.GET.copy()
    if "page" in query:
        del query["page"]
        
    c = Context({ "query" : urlencode(query),
              "page" : r.results() })
    
    response = HttpResponse(t.render(c))
    return response

import re
_json_url_re = re.compile("/{0,1}(?P<base>.*)/json/{0,1}(\?.*){0,1}$")
def results_json(request, app_label, model_name):
    model = get_model_or_404(app_label, model_name)
    
    results = ResultList(request, model).results()

    labels = get_display_labels(model)
    json = {
        "metaData": { "totalProperty": 'results',
                  "root": 'rows',
                  "id": 'id' },
        "results": results.paginator.count,
        "rows": []
        }

    m = _json_url_re.match(request.META["PATH_INFO"])
    if m:
        path = settings.WWW_HOST + m.groupdict()["base"] + "/%s/json/"
    else:
        print "aiee -- bad path no json?!", request.META["PATH_INFO"]
        path = None

    for obj in results.object_list:
        row = map(lambda x: (x[0], unicode(x[1])), get_display_fields(obj))
        row.insert(0, ("fid", obj.pk))
        if path:
            row.insert(0, ("json", path % obj.pk))
        json["rows"].append(dict(row))
        if not json["metaData"].get("fields"):
            fields = map(lambda x: { "name" : x[0] }, row)
            json["metaData"]["fields"] = fields
    response = HttpResponse()
    response.write(simplejson.dumps(json))
    return response

def results_kml(request, app_label, model_name):
    model = get_model_or_404(app_label, model_name)
    doc = libxml2.newDoc("1.0")
    kml = doc.newChild(None, "kml", None)
    kmlns = kml.newNs("http://earth.google.com/kml/2.0", None)
    kml.setNs(kmlns)
    root = kml.newChild(kmlns, "Document", None)
    
    results = ResultList(request, model).results()
    labels = get_display_labels(model)
    for obj in results.object_list:
        mark = root.newChild(kmlns, "Placemark", None)
        #mark.setProp("id", "%s_%s_%s" % (obj._meta.app_label,
        #                 obj._meta.module_name,
        #                 obj.pk))
        mark.setProp("id", "%s" % obj.pk)
        mark.newChild(kmlns, "name", unicode(obj))
        description = []
        values = map(lambda x: x[1], get_display_fields(obj))
        for label, value in zip(labels, values):
            s = """<b>%s</b>: %s""" % (unicode(label), unicode(value))
            description.append(s)
        description = libxml2.newText("<br/>".join(description))
        dnode = mark.newChild(kmlns, "description", None)
        dnode.addChild(description)

        if model._meta.search.geometry_field:
            geom = getattr(obj, model._meta.search.geometry_field)
            if geom:
                kgeomdoc = libxml2.parseDoc(geom.kml)
                kgeom = kgeomdoc.children
                kgeom.unlinkNode()
                kgeomdoc.freeDoc()
                mark.addChild(kgeom)
            
    response = HttpResponse()
    response["Content-Type"] = "text/plain"
    response.write(doc.serialize("utf-8", True))
    doc.freeDoc()

    return response
    
